MCP Servers
MCP (Model Context Protocol) allows you to connect external tool servers to your agent. MCP servers run as separate processes and expose tools over a standardized protocol.
What is MCP?
MCP is a protocol for connecting AI agents to external tools. Instead of writing C# code for each integration, you can:
- Use existing MCP servers (filesystem, GitHub, databases, etc.)
- Connect to any MCP-compatible server
- Get automatic tool discovery
Agent ←──MCP Protocol──→ MCP Server (filesystem)
←──MCP Protocol──→ MCP Server (github)
←──MCP Protocol──→ MCP Server (database)Quick Start
1. Create a Manifest File
Create MCP.json:
{
"servers": [
{
"name": "filesystem",
"command": "npx",
"arguments": ["-y", "@anthropic/mcp-filesystem", "/workspace"],
"description": "File operations within workspace",
"enabled": true
}
]
}2. Register with AgentBuilder
var agent = await new AgentBuilder()
.WithMCP("./MCP.json")
.Build();That's it! The agent now has access to all tools from the filesystem MCP server.
Manifest Configuration
MCPServerConfig Properties
| Property | Type | Default | Description |
|---|---|---|---|
name | string | required | Unique identifier for the server |
command | string | required | Command to start the server |
arguments | string[] | [] | Command arguments |
description | string | null | Description shown when collapsed |
enabled | bool | true | Whether to load this server |
enablecollapsing | bool | null | Group tools under a container |
requiresPermission | bool | true | Require user approval for tools |
functionResult | string | null | One-time message on expansion (appended to auto-generated) |
systemPrompt | string | null | Persistent instructions (injected into system prompt) |
timeout | int | 30000 | Connection timeout in ms |
retryAttempts | int | 3 | Number of retry attempts |
environment | object | null | Environment variables |
Full Example
{
"servers": [
{
"name": "filesystem",
"command": "npx",
"arguments": ["-y", "@anthropic/mcp-filesystem", "/workspace"],
"description": "File operations within workspace",
"enabled": true,
"enablecollapsing": true,
"requiresPermission": true,
"functionResult": "Working directory: /workspace",
"systemPrompt": "Never write outside /workspace. Always use absolute paths.",
"timeout": 30000,
"retryAttempts": 3,
"environment": {
"NODE_ENV": "production"
}
},
{
"name": "github",
"command": "npx",
"arguments": ["-y", "@anthropic/mcp-github"],
"description": "GitHub repository operations",
"enabled": true,
"enablecollapsing": true,
"systemPrompt": "Use search before listing all PRs. Always include PR descriptions.",
"environment": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
]
}Registration Methods
From Manifest File
var agent = await new AgentBuilder()
.WithMCP("./MCP.json")
.Build();With Options
var agent = await new AgentBuilder()
.WithMCP("./MCP.json", options =>
{
options.FailOnServerError = false; // Continue if a server fails
options.ConnectionTimeout = TimeSpan.FromSeconds(30);
options.MaxConcurrentServers = 10;
})
.Build();From JSON String
var manifest = @"{
""servers"": [
{
""name"": ""filesystem"",
""command"": ""npx"",
""arguments"": [""-y"", ""@anthropic/mcp-filesystem""]
}
]
}";
var agent = await new AgentBuilder()
.WithMCPContent(manifest)
.Build();Collapsing
When enablecollapsing is true, all tools from a server are grouped under a container:
Before expansion: After expansion:
┌─────────────────────┐ ┌─────────────────────┐
│ MCP_filesystem │ ──► │ read_file │
│ (5 functions) │ │ write_file │
└─────────────────────┘ │ list_directory │
│ create_directory │
│ delete_file │
└─────────────────────┘Container Naming
Containers are named MCP_{serverName}:
filesystem→MCP_filesystemgithub→MCP_github
Enable Collapsing
In manifest:
{
"name": "filesystem",
"enablecollapsing": true,
"description": "File operations"
}The description appears in the container's tool definition.
Server Instructions
MCP servers support the same dual-context architecture as C# tools and Client tools:
| Parameter | Location | Lifetime | Use For |
|---|---|---|---|
functionResult | Conversation history | One-time on expansion | Additional context (appended to auto-generated message) |
systemPrompt | System prompt | Every turn while expanded | Critical rules, workflow |
** Requires Collapsing:**
functionResultandsystemPromptonly work whenenablecollapsing: true. If collapsing is disabled, instructions are ignored and validation will fail.
Important: The system automatically generates a base expansion message:
"{serverName} server expanded. Available functions: {FunctionList}"Your
functionResultis appended to this auto-generated message. Don't duplicate the expansion info—use it only for additional context. Passnullif the auto-generated message is sufficient.
In Manifest (Recommended)
{
"name": "filesystem",
"command": "npx",
"arguments": ["-y", "@anthropic/mcp-filesystem", "/workspace"],
"description": "File operations within workspace",
"enablecollapsing": true,
"functionResult": "Working directory: /workspace",
"systemPrompt": "Never write outside /workspace. Always use absolute paths."
}Via AgentConfig (Legacy)
You can also provide instructions via MCPServerInstructions in AgentConfig. These are injected as SystemPrompt (persistent):
var config = new AgentConfig
{
Collapsing = new CollapsingConfig
{
MCPServerInstructions = new Dictionary<string, string>
{
["filesystem"] = @"
FILESYSTEM RULES:
- Always use absolute paths
- Check if file exists before reading
- Never write outside /workspace"
}
}
};Note: Manifest-level
systemPromptandMCPServerInstructionsboth provide persistent instructions. Use the manifest approach for new projects.
Permissions
By default, MCP tools require user permission (requiresPermission: true). This is a safety feature since MCP servers can perform arbitrary operations.
Disable for Trusted Servers
{
"name": "readonly-docs",
"command": "npx",
"arguments": ["-y", "@example/docs-server"],
"requiresPermission": false
}Only disable for read-only or trusted servers.
Environment Variables
Pass environment variables to MCP servers:
{
"name": "github",
"command": "npx",
"arguments": ["-y", "@anthropic/mcp-github"],
"environment": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}",
"GITHUB_ORG": "my-org"
}
}Use ${VAR_NAME} syntax to reference system environment variables.
Common MCP Servers
| Server | Package | Description |
|---|---|---|
| Filesystem | @anthropic/mcp-filesystem | Read/write files |
| GitHub | @anthropic/mcp-github | Repository operations |
| PostgreSQL | @anthropic/mcp-postgres | Database queries |
| Brave Search | @anthropic/mcp-brave-search | Web search |
| Memory | @anthropic/mcp-memory | Persistent key-value store |
Example: Multiple Servers
{
"servers": [
{
"name": "filesystem",
"command": "npx",
"arguments": ["-y", "@anthropic/mcp-filesystem", "/workspace"],
"enablecollapsing": true
},
{
"name": "github",
"command": "npx",
"arguments": ["-y", "@anthropic/mcp-github"],
"enablecollapsing": true,
"environment": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
},
{
"name": "search",
"command": "npx",
"arguments": ["-y", "@anthropic/mcp-brave-search"],
"enablecollapsing": false,
"environment": {
"BRAVE_API_KEY": "${BRAVE_API_KEY}"
}
}
]
}Error Handling
Server Startup Failures
By default, if one server fails to start, the agent continues with others:
.WithMCP("./MCP.json", options =>
{
options.FailOnServerError = false; // Default
})Set FailOnServerError = true to fail fast if any server fails.
Timeouts
Configure connection timeout:
.WithMCP("./MCP.json", options =>
{
options.ConnectionTimeout = TimeSpan.FromSeconds(60);
})Or per-server in manifest:
{
"name": "slow-server",
"timeout": 60000
}Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| Server not found | command not in PATH | Use full path or ensure npx is available |
| Tools not appearing | enabled: false | Set enabled: true |
| Permission denied | Server needs API key | Check environment variables |
| Timeout | Server slow to start | Increase timeout |
Debug: Check Loaded Tools
var agent = await new AgentBuilder()
.WithMCP("./MCP.json")
.Build();
// List all tools
foreach (var tool in agent.Tools)
{
Console.WriteLine($"{tool.Name}: {tool.Description}");
}Best Practices
Use collapsing for servers with many tools to reduce context clutter.
Set requiresPermission: true for servers that can modify data.
Provide descriptions to help the agent understand what each server does.
Use environment variables for secrets—never hardcode tokens.
Set appropriate timeouts based on server startup time.
Use dual-context instructions: Put critical rules in
systemPrompt, additional context infunctionResult.Don't duplicate auto-generated messages in
functionResult—they waste tokens.
{
"name": "database",
"command": "npx",
"arguments": ["-y", "@example/mcp-postgres"],
"description": "Query the production database (read-only)",
"enablecollapsing": true,
"requiresPermission": true,
"functionResult": "Connected to: production (read-only)",
"systemPrompt": "LIMIT all queries to 1000 rows. Never use DELETE or UPDATE.",
"timeout": 10000,
"environment": {
"DATABASE_URL": "${DATABASE_URL}"
}
}